package com.carbohydrate42.kotlin_compose_demo.compose

import android.Manifest
import android.content.Context
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.camera.core.Camera
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.ImageProxy
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.zIndex
import androidx.lifecycle.LifecycleOwner
import com.carbohydrate42.kotlin_compose_demo.util.DebugUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import java.util.Date


@Preview(showBackground = true, showSystemUi = true)
@Composable
fun TryCameraX() {

    var isGranted by remember { mutableStateOf(false) }

    // 动态请求一下 CAMERA 权限 (不然会黑屏而且还不报错)
    val requestPermission =
        rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) {
            isGranted = it
        }

    LaunchedEffect(Unit) {
        requestPermission.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
    }

    if (isGranted) {
        CameraXScreen()
    } else {
        Text(text = "没有权限")
    }
}


suspend fun initCamera(
    lifecycleOwner: LifecycleOwner,
    context: Context,
    previewView: PreviewView,
    isBackCamera: Boolean
): Triple<ProcessCameraProvider, Camera, ImageCapture> {

    val cameraProvider = withContext(Dispatchers.IO) {
        ProcessCameraProvider.getInstance(context).get()
    }

    // 先解绑所有 useCase
    cameraProvider.unbindAll()

    // 相机选择器
    val cameraSelector = if (
        cameraProvider.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA)
        && isBackCamera
    ) {
        CameraSelector.DEFAULT_BACK_CAMERA
    } else if (
        cameraProvider.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA)
        && !isBackCamera
    ) {
        CameraSelector.DEFAULT_FRONT_CAMERA
    } else {
        throw IllegalArgumentException("No available cameras on the device")
    }

    // useCase : 相机画面预览 (绑定 previewView)
    val previewUseCase = androidx.camera.core.Preview.Builder().build().apply {
        setSurfaceProvider(previewView.surfaceProvider)
    }


    // useCase : 拍照
    val imageCaptureUseCase = ImageCapture.Builder().build().apply {
        targetRotation = previewView.display.rotation
    }


    // 绑定 useCase
    val camera = cameraProvider.bindToLifecycle(
        // 绑定 compose 的生命周期
        lifecycleOwner,

        // 摄像头
        cameraSelector,

        // 预览
        previewUseCase,

        // 拍照
        imageCaptureUseCase
    )


    return Triple(cameraProvider, camera, imageCaptureUseCase)
}


@Composable
fun CameraXScreen() {
    var enableTorch by remember {
        mutableStateOf(false)
    }

    var enableTorchEnabled by remember {
        mutableStateOf(false)
    }

    var isBackCamera by remember {
        mutableStateOf(true)
    }

    var cameraSwitchEnabled by remember {
        mutableStateOf(false)
    }

    val lifecycleOwner = LocalLifecycleOwner.current
    val context = LocalContext.current

    // 加了 remember 是为了防止重复创建 PreviewView, compose 会自动帮你缓存
    val previewView = remember {
        PreviewView(context)
    }

    // 用 mutableStateOf 来缓存 Camera 对象, 主要是为了 enableTorch 的 LaunchedEffect, 而且切换摄像头的时候也要重新创建 Camera
    var mCamera by remember {
        mutableStateOf<Camera?>(null)
    }

    var mImageCaptureUseCase by remember {
        mutableStateOf<ImageCapture?>(null)
    }

    LaunchedEffect(Unit) {
        val (cameraProvider, camera, imageCaptureUseCase) = initCamera(
            lifecycleOwner = lifecycleOwner,
            context = context,
            previewView = previewView,
            isBackCamera = isBackCamera
        )

        cameraSwitchEnabled = cameraProvider.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA)
        enableTorchEnabled = camera.cameraInfo.hasFlashUnit()

        mCamera = camera
        mImageCaptureUseCase = imageCaptureUseCase
    }

    LaunchedEffect(enableTorch) {
        if (enableTorch) {
            mCamera?.cameraControl?.enableTorch(true)
        } else {
            mCamera?.cameraControl?.enableTorch(false)
        }
    }

    LaunchedEffect(isBackCamera) {
        val (cameraProvider, camera, imageCaptureUseCase) = initCamera(
            lifecycleOwner = lifecycleOwner,
            context = context,
            previewView = previewView,
            isBackCamera = isBackCamera
        )

        cameraSwitchEnabled = cameraProvider.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA)
        enableTorchEnabled = camera.cameraInfo.hasFlashUnit()

        mCamera = camera
        mImageCaptureUseCase = imageCaptureUseCase
    }


    Column(
        modifier = Modifier
            .fillMaxSize()
            .zIndex(1.0f),
        verticalArrangement = Arrangement.Bottom,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceBetween
        ) {
            Button(
                onClick = {
                    isBackCamera = !isBackCamera
                },
                enabled = cameraSwitchEnabled

            ) {
                Text(text = "flip")
            }

            Button(
                onClick = {
                    mImageCaptureUseCase?.takePicture(
                        ImageCapture.OutputFileOptions.Builder(
                            // todo : 报错 Failed to write temp file
                            File(
                                "${context.externalCacheDir}${File.separator}${System.currentTimeMillis()}.jpg"
                            )
                        ).build(),
                        context.mainExecutor,
                        object : ImageCapture.OnImageSavedCallback {
                            override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
                                DebugUtil.toast("${outputFileResults.savedUri}")
                            }

                            override fun onError(exception: ImageCaptureException) {
                                DebugUtil.exceptionLog(exception, "onError")
                            }
                        }
                    )
                }
            ) {
                Text(text = "take picture")
            }



            Button(
                onClick = {
                    enableTorch = !enableTorch
                },
                enabled = enableTorchEnabled
            ) {
                Text(text = if (enableTorch) "light off" else "light on")
            }
        }
    }

    AndroidView(
        factory = { previewView },
        modifier = Modifier
            .fillMaxSize()
            .zIndex(0.0f)
    )
}
